﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing.Design;
using System.Web.UI;

namespace SCS.Web.UI.WebControls
{
    /// <summary>
    /// Contains the child <see cref="HierListItem"/> items for a parent <see cref="HierListItem"/>.
    /// </summary>
    public sealed class HierListItemCollection : IList, IStateManager
    {
        #region Fields

        private HierList _root;
        private ArrayList _items;
        private bool _isTrackingViewState;
        private bool _saveAll;

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="HierListItemCollection"/> class.
        /// </summary>
        public HierListItemCollection()
        {
            _items = new ArrayList();
        }

        /// <summary>
        /// Gets the <see cref="SCS.Web.UI.WebControls.HierListItem"/> at the specified index.
        /// </summary>
        /// <value></value>
        public HierListItem this[int index]
        {
            get
            {
                return (HierListItem)_items[index];
            }
        }
        object IList.this[int index]
        {
            get
            {
                return _items[index];
            }
            set
            {
                _items[index] = (HierListItem)value;
            }
        }
        /// <summary>
        /// Adds the specified item.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <returns></returns>
        public int Add(HierListItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("Item cannot be null.");
            }

            _items.Add(item);

            if (_isTrackingViewState)
            {
                ((IStateManager)item).TrackViewState();
                item.SetDirty();
            }

            return _items.Count - 1;
        }
        /// <summary>
        /// Removes all items from the <see cref="T:System.Collections.IList"/>.
        /// </summary>
        /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.IList"/> is read-only. </exception>
        public void Clear()
        {
            _items.Clear();
            if (_isTrackingViewState)
            {
                _saveAll = true;
            }
        }
        /// <summary>
        /// Determines whether [contains] [the specified item].
        /// </summary>
        /// <param name="item">The item.</param>
        /// <returns>
        /// 	<c>true</c> if [contains] [the specified item]; otherwise, <c>false</c>.
        /// </returns>
        public bool Contains(HierListItem item)
        {
            if (item == null)
            {
                return false;
            }
            return _items.Contains(item);
        }
        /// <summary>
        /// Indexes the of.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <returns></returns>
        public int IndexOf(HierListItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("Item cannot be null.");
            }
            return _items.IndexOf(item);
        }
        /// <summary>
        /// Inserts the specified index.
        /// </summary>
        /// <param name="index">The index.</param>
        /// <param name="item">The item.</param>
        public void Insert(int index, HierListItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("Item cannot be null.");
            }

            _items.Insert(index, item);

            if (_isTrackingViewState)
            {
                ((IStateManager)item).TrackViewState();
                _saveAll = true;
            }
        }
        /// <summary>
        /// Removes the <see cref="T:System.Collections.IList"/> item at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index of the item to remove.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// 	<paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.IList"/>. </exception>
        /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.IList"/> is read-only.-or- The <see cref="T:System.Collections.IList"/> has a fixed size. </exception>
        public void RemoveAt(int index)
        {
            _items.RemoveAt(index);
            if (_isTrackingViewState)
            {
                _saveAll = true;
            }
        }
        /// <summary>
        /// Removes the specified item.
        /// </summary>
        /// <param name="item">The item.</param>
        public void Remove(HierListItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("Item cannot be null.");
            }

            int index = IndexOf(item);
            if (index >= 0)
            {
                RemoveAt(index);
            }
        }

        #region IEnumerable Implementation
        /// <summary>
        /// Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
        /// </returns>
        public IEnumerator GetEnumerator()
        {
            return _items.GetEnumerator();
        }
        #endregion IEnumerable Implementation

        #region ICollection Implementation
        /// <summary>
        /// Gets the number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
        /// </summary>
        /// <value></value>
        /// <returns>The number of elements contained in the <see cref="T:System.Collections.ICollection"/>.</returns>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public int Count
        {
            get
            {
                return _items.Count;
            }
        }

        /// <summary>
        /// Copies the elements of the <see cref="T:System.Collections.ICollection"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
        /// </summary>
        /// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.ICollection"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param>
        /// <param name="index">The zero-based index in <paramref name="array"/> at which copying begins.</param>
        /// <exception cref="T:System.ArgumentNullException">
        /// 	<paramref name="array"/> is null. </exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// 	<paramref name="index"/> is less than zero. </exception>
        /// <exception cref="T:System.ArgumentException">
        /// 	<paramref name="array"/> is multidimensional.-or- The number of elements in the source <see cref="T:System.Collections.ICollection"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>. </exception>
        /// <exception cref="T:System.ArgumentException">The type of the source <see cref="T:System.Collections.ICollection"/> cannot be cast automatically to the type of the destination <paramref name="array"/>. </exception>
        public void CopyTo(Array array, int index)
        {
            _items.CopyTo(array, index);
        }

        /// <summary>
        /// Gets a value indicating whether access to the <see cref="T:System.Collections.ICollection"/> is synchronized (thread safe).
        /// </summary>
        /// <value></value>
        /// <returns>true if access to the <see cref="T:System.Collections.ICollection"/> is synchronized (thread safe); otherwise, false.</returns>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public bool IsSynchronized
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.
        /// </summary>
        /// <value></value>
        /// <returns>An object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.</returns>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public object SyncRoot
        {
            get
            {
                return this;
            }
        }
        #endregion ICollection Implementation

        #region IList Implementation
        bool IList.IsFixedSize
        {
            get
            {
                return false;
            }
        }
        bool IList.IsReadOnly
        {
            get
            {
                return false;
            }
        }
        int IList.Add(object item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            if (!(item is HierListItem))
            {
                throw new ArgumentException("item must be a UlItem");
            }

            return Add((HierListItem)item);
        }
        void IList.Clear()
        {
            Clear();
        }
        bool IList.Contains(object item)
        {
            return Contains(item as HierListItem);
        }
        int IList.IndexOf(object item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            if (!(item is HierListItem))
            {
                throw new ArgumentException("item must be a UlItem");
            }

            return IndexOf((HierListItem)item);
        }
        void IList.Insert(int index, object item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            if (!(item is HierListItem))
            {
                throw new ArgumentException("item must be a UlItem");
            }

            Insert(index, (HierListItem)item);
        }
        void IList.Remove(object item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            if (!(item is HierListItem))
            {
                throw new ArgumentException("item must be a UlItem");
            }

            Remove((HierListItem)item);
        }
        void IList.RemoveAt(int index)
        {
            RemoveAt(index);
        }
        #endregion IList Implementation

        #region IStateManager Implementation
        
        bool IStateManager.IsTrackingViewState
        {
            get
            {
                return _isTrackingViewState;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is tracking view state_.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is tracking view state_; otherwise, <c>false</c>.
        /// </value>
        public bool IsTrackingViewState_
        {
            get
            {
                return _isTrackingViewState;
            }
        }

        void IStateManager.LoadViewState(object savedState)
        {
            if (savedState == null)
            {
                return;
            }

            if (savedState is Pair)
            {
                // All items were saved.
                // Create new UlItem collection using view state.
                _saveAll = true;
                Pair p = (Pair)savedState;
                ArrayList types = (ArrayList)p.First;
                ArrayList states = (ArrayList)p.Second;
                int count = types.Count;

                _items = new ArrayList(count);
                for (int i = 0; i < count; i++)
                {
                    HierListItem item = null;
                    if (((char)types[i]).Equals('c'))
                    //{
                        item = ControlRoot.CreateItemInternal();
                    //}
                    //else 
                    //{

                    //}
                    Add(item);
                    ((IStateManager)item).LoadViewState(states[i]);
                }
            }
            else
            {
                // Load modified items.
                Triplet t = (Triplet)savedState;
                ArrayList indices = (ArrayList)t.First;
                ArrayList types = (ArrayList)t.Second;
                ArrayList states = (ArrayList)t.Third;

                for (int i = 0; i < indices.Count; i++)
                {
                    int index = (int)indices[i];
                    if (index < this.Count)
                    {
                        foreach (HierListItem item in _items)
                            item.ControlRoot = _root;

                        ((IStateManager)_items[index]).LoadViewState(states[i]);
                    }
                    else
                    {
                        HierListItem item = null;
                        //if (((char)types[i]).Equals('c')) 
                        //{
                            item = ControlRoot.CreateItemInternal();
                        //}
                        //else 
                        //{

                        //}
                        Add(item);
                        ((IStateManager)item).LoadViewState(states[i]);
                    }
                }
            }
        }
        void IStateManager.TrackViewState()
        {
            _isTrackingViewState = true;

            if (_items != null)
            {
                foreach (HierListItem tabItem in _items)
                {
                    ((IStateManager)tabItem).TrackViewState();
                }
            }
        }
        object IStateManager.SaveViewState()
        {
            if (_saveAll == true)
            {
                // Save all items.
                ArrayList types = new ArrayList(Count);
                ArrayList states = new ArrayList(Count);
                for (int i = 0; i < Count; i++)
                {
                    HierListItem tabItem = (HierListItem)_items[i];
                    tabItem.SetDirty();

                    //if (tabItem is UlItem) 
                    //{
                    types.Add('c');
                    //}
                    //else 
                    //{
                    //	types.Add('r');
                    //}
                    states.Add(((IStateManager)tabItem).SaveViewState());
                }
                if (types.Count > 0)
                {
                    return new Pair(types, states);
                }
                else
                {
                    return null;
                }
            }
            else
            {
                // Save only the dirty items.
                ArrayList indices = new ArrayList();
                ArrayList types = new ArrayList();
                ArrayList states = new ArrayList();

                for (int i = 0; i < Count; i++)
                {
                    HierListItem tabItem = (HierListItem)_items[i];
                    object state = ((IStateManager)tabItem).SaveViewState();
                    if (state != null)
                    {
                        states.Add(state);
                        indices.Add(i);

                        //if (tabItem is UlItem) 
                        //{
                        types.Add('c');
                        //}
                        //else 
                        //{
                        //	types.Add('r');
                        //}
                    }
                }

                if (indices.Count > 0)
                {
                    return new Triplet(indices, types, states);
                }

                return null;
            }
        }

        #endregion IStateManager Implementation

        /// <summary>
        /// Gets or sets the control root.
        /// </summary>
        /// <value>The control root.</value>
        [Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        internal HierList ControlRoot
        {
            get
            {
                return _root;
            }
            set
            {
                _root = value;
            }
        }
    }
}
